package com.gjy.util.sb.aop.aspect;

import com.gjy.util.sb.aop.annotation.PreCheckId;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * @author 宫静雨
 * @version 1.0
 * @since 2023-10-23 10:35:35
 */
@Aspect
@Component
@Order(0)
public class PreCheckIdAspect {

    private static final Logger log = LoggerFactory.getLogger(PreCheckIdAspect.class);

    /**
     * 获取方法参数定义名
     */
    private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
    /**
     * 用于 SPEL 表达式解析
     */
    private final SpelExpressionParser parser = new SpelExpressionParser();

    @Around("@annotation(preCheckId)")
    public Object aroundCheckId(ProceedingJoinPoint point,
                                PreCheckId preCheckId) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        String userId = getValBySpEl(preCheckId.userId(), signature, point.getArgs());
        String t2 = getValBySpEl(preCheckId.t2(), signature, point.getArgs());
        log.info("userId: {}, t2: {}", userId, t2);
        // 针对 userId 的值进行验证
        if (Objects.nonNull(userId) && userId.equals("999")) {
            return "userId 不可用 999";
        }
        Object proceed = point.proceed();
        log.info("proceed: {}", proceed);
        return proceed;
    }

    /**
     * 解析spEL表达式
     *
     * @param spEl            spel表达式
     * @param methodSignature methodSignature
     * @param args            args
     * @return string
     */
    private String getValBySpEl(String spEl, MethodSignature methodSignature, Object[] args) {
        //获取方法形参名数组
        String[] paramNames = discoverer.getParameterNames(methodSignature.getMethod());
        if (paramNames != null && paramNames.length > 0) {
            Expression expression = parser.parseExpression(spEl);
            // spring的表达式上下文对象
            EvaluationContext context = new StandardEvaluationContext();
            // 给上下文赋值
            for (int i = 0; i < args.length; i++) {
                //设置变量
                context.setVariable(paramNames[i], args[i]);
            }
            return Objects.requireNonNull(expression.getValue(context)).toString();
        }
        return null;
    }

}
